package com.piece.core.log.config;

import com.piece.core.framework.util.basic.SpringUtil;
import com.piece.core.framework.util.object.ClassUtil;
import com.piece.core.log.annotation.AuditLogFunc;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 注册自定义函数
 */
@Data
@Slf4j
public class AuditLogFunctionRegister implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    private static Map<String, Method> functionMap = new HashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        Map<String, Object> beanWithAnnotation = applicationContext.getBeansWithAnnotation(AuditLogFunc.class);

        beanWithAnnotation.values().forEach(component -> {
            Method[] methods = component.getClass().getMethods();
            StringBuilder prefixName = new StringBuilder();

            try {
                Object originalClass = SpringUtil.getProxy(component);
                AuditLogFunc func = originalClass.getClass().getAnnotation(AuditLogFunc.class);
                prefixName.append(func.value());
                if (StringUtils.hasText(prefixName)) {
                    prefixName.append("_");
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                throw new RuntimeException(e);
            }

            if (methods.length > 0) {
                Map<Method, AuditLogFunc> annotationMap = new HashMap<>();
                for (Method method : methods) {
                    AuditLogFunc annotation = AnnotatedElementUtils.findMergedAnnotation(method, AuditLogFunc.class);
                    if (null != annotation) {
                        annotationMap.put(method, annotation);
                    }
                }
                // 静态方法直接调用
                annotationMap.keySet().stream().filter(ClassUtil::isStaticMethod).forEach(method -> {
                    AuditLogFunc annotation = annotationMap.get(method);
                    String registerName = StringUtils.hasText(annotation.value()) ? annotation.value() : method.getName();
                    functionMap.put(prefixName + registerName, method);
                    if (log.isDebugEnabled()) {
                        log.debug("AuditLogFunc register static function [{}] as name [{}]", method, prefixName + registerName);
                    }
                });
            }
        });
    }

    public static void register(StandardEvaluationContext context) {
        functionMap.forEach(context::registerFunction);
    }
}
